package org.trc.traffic.analysis;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import org.geotools.data.shapefile.shp.ShapefileException;
import org.geotools.feature.SchemaException;


/**
 * Road_Cluster:(Multilinkid, soffset, eoffset, sTime, eTime, linkid_1, dur_1, ....linkid_n, dur_n)
 * 
 * @author Administrator
 *
 */

public class STMLinkCongestionClustering extends STLinkCongestionClustering {
	protected float maxMLinkDistance;

	protected int maxMLinkTimeInterval;
		
	public void buildCongestionCluster(String mLinkID, int startHour, int endHour, Date day, float maxDistance, int maxTimeInterval) {
		if(road == null)
			this.initial();
		
		this.maxMLinkDistance = maxDistance;
		
		this.maxMLinkTimeInterval = maxTimeInterval;
		
	    //数据集初始化
		ArrayList <LinkCongestionCluster> allLinkClusterList = new ArrayList <LinkCongestionCluster> ();	
		ArrayList <String> edgeIDList = road.multiLinkCollection.get(mLinkID).edgeIDList;
		
		for(String edgeID : edgeIDList){
			super.buildCongestionCluster(edgeID, startHour, endHour, day, 0, 2);
			//allLinkClusterList.addAll((Collection<? extends LinkCongestionCluster>) super.getVIPCongestionCluster(2));
			allLinkClusterList.addAll((Collection<? extends LinkCongestionCluster>) super.getCongestionCluster());
		}
		
		Map<String, CongestionCluster> mLinkCongestionClusterSet = Collections.synchronizedMap(new HashMap<String, CongestionCluster>());
		
		//LinkCongestionCluster分组
		int clusterNum = 1;	
		LinkCongestionCluster linkCC = null;
		
		for (int i = 0; i < allLinkClusterList.size(); i++) {
			linkCC = (LinkCongestionCluster)allLinkClusterList.get(i);
			if (linkCC.clusterID.startsWith("link")) {// 未分组  
				this.expandCongestionCluster(linkCC, allLinkClusterList,  mLinkID, clusterNum + "_" + dateFormat.format(day));
				clusterNum++;
			}
		}
		
		//生成 MLinkCongestionCluster		
		MLinkCongestionCluster congestionCluster = null;
		
		for (LinkCongestionCluster lCC : allLinkClusterList){
			String clusterID = lCC.clusterID;
			if (!mLinkCongestionClusterSet.containsKey(clusterID)) {
				congestionCluster = new MLinkCongestionCluster(clusterID);
				congestionCluster.mLinkID = mLinkID;
				mLinkCongestionClusterSet.put(clusterID, congestionCluster);
			}
			congestionCluster = (MLinkCongestionCluster)mLinkCongestionClusterSet.get(clusterID);			
			congestionCluster.add(lCC, road.getEdgeById(lCC.linkid).getLinearStartOffest(mLinkID), road.getEdgeById(lCC.linkid).getLinearEndOffset(mLinkID));
		}
				
		//	
		this.congestionClusterSet = mLinkCongestionClusterSet;
	}	

	private void expandCongestionCluster(LinkCongestionCluster coreLinkCluster, ArrayList<LinkCongestionCluster> allLinkClusterList, String mLinkID, String clusterNum){			
		coreLinkCluster.clusterID = "Mlink_"+ mLinkID + "_" + clusterNum;
		
		List<LinkCongestionCluster> resultDataSet = this.STRangeQuery(coreLinkCluster, allLinkClusterList, mLinkID);
		
		if(resultDataSet.size() == 0)
			return;
	
		for (LinkCongestionCluster lCC : resultDataSet) {// 标记簇ID
			if(lCC.clusterID.startsWith("link"))
				expandCongestionCluster(lCC, allLinkClusterList, mLinkID, clusterNum);
		}			
	}
	
	// 时空邻域查询
	private List<LinkCongestionCluster> STRangeQuery(LinkCongestionCluster coreLinkCluster, ArrayList<LinkCongestionCluster> allLinkClusterList, String MLinkID) {
		Vector<LinkCongestionCluster> stRange_List = new Vector<LinkCongestionCluster>();
		
		for (LinkCongestionCluster lCC : allLinkClusterList) {
			if(lCC.equals(coreLinkCluster))
				continue;
			if (timeWithin(lCC, coreLinkCluster)&& spatialWithin(lCC, coreLinkCluster, MLinkID))
				stRange_List.add(lCC);
		}
		
		return stRange_List;
	}

	// 时间间隔
	private boolean timeWithin(LinkCongestionCluster lCC1, LinkCongestionCluster lCC2) {
		if((lCC1.startTime - lCC2.endTime)> maxMLinkTimeInterval || (lCC2.startTime - lCC1.endTime) > maxMLinkTimeInterval )
			return false;
		else
			return true;
	}

	// 空间距离(线性距离的计算)
	private boolean spatialWithin(LinkCongestionCluster lCC1, LinkCongestionCluster lCC2, String MLinkID) {
		if (road.linearDistance(lCC1.linkid, lCC2.linkid, MLinkID) < this.maxMLinkDistance) {
			return true;
		} else
			return false;
	}
	
	// 获取重要的簇
	public ArrayList <CongestionCluster> getVIPCongestionCluster(int minDur, int minLength) {
		ArrayList <CongestionCluster> vipCongestionClusterList = new ArrayList <CongestionCluster> ();
	
		for(CongestionCluster cc : this.getCongestionCluster()){
			MLinkCongestionCluster mlcc = (MLinkCongestionCluster)cc;
			if(mlcc.dur >= minDur && mlcc.length >= minLength)
				vipCongestionClusterList.add(mlcc);			
		}
		
		return vipCongestionClusterList;
	}
	
	public static void main(String[] args) throws ShapefileException, IOException, ParseException, SchemaException {
		STMLinkCongestionClustering stCongestionCluster = new STMLinkCongestionClustering();
		
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-mm-dd");		
		
		stCongestionCluster.buildCongestionCluster("31611", 7, 8, dateFormat.parse("2009-3-12"), 300, 2);

		// 遍历簇
		ArrayList<CongestionCluster> congestionClusters = stCongestionCluster.getCongestionCluster();
		
		for (CongestionCluster congestionCluster : congestionClusters) {
			MLinkCongestionCluster cc = (MLinkCongestionCluster)congestionCluster;
			
			stCongestionCluster.road.getLineByLinearReference(cc.mLinkID, cc.startOffset, cc.endOffset);
			
			System.out.print("CluterID: " + cc.clusterID + ",");
			System.out.print(" StartTime: " + (cc.startTime-84) + ",");
			System.out.print(" EndtTime: " + (cc.endTime - 84));
			System.out.print(" SOFFSET: " + cc.startOffset );
			System.out.print(" EOFFSET: " + cc.endOffset );
			System.out.println();
		}
	}

}

